#include "planner/property_set.h"

#include "common/hash_util.h"

namespace optimizer {

void PropertySet::AddProperty(Property *property) {
  LOG_PRINTLN("Add property with type %d", static_cast<int>(property->Type()));
  auto iter = properties_.begin();
  for (; iter != properties_.end(); iter++) {
    // Iterate until point where preserve descending order
    if (property->Type() < (*iter)->Type()) {
      break;
    }
  }

  properties_.insert(iter, property);
}

const Property *PropertySet::GetPropertyOfType(PropertyType type) const {
  for (const auto &prop : properties_) {
    if (prop->Type() == type) {
      return prop;
    }
  }

  LOG_PRINTLN("Didn't find property with type %d", static_cast<int>(type));
  return nullptr;
}

bool PropertySet::HasProperty(const Property &r_property) const {
  for (auto *property : properties_) {
    if (*property >= r_property) {
      return true;
    }
  }

  return false;
}

bool PropertySet::operator>=(const PropertySet &r) const {
  for (auto *r_property : r.properties_) {
    if (!HasProperty(*r_property))
      return false;
  }
  return true;
}

bool PropertySet::operator==(const PropertySet &r) const {
  return *this >= r && r >= *this;
}

hash_t PropertySet::Hash() const {
  size_t prop_size = properties_.size();
  hash_t hash = HashUtil::Hash<size_t>(prop_size);
  for (const auto &prop : properties_) {
    hash = HashUtil::CombineHashes(hash, prop->Hash());
  }
  return hash;
}

std::string PropertySet::ToString() const {
  std::string result;
  for (const auto &prop : properties_) {
    result += prop->ToString() + ", ";
  }
  return result;
}

}  // namespace optimizer
